/*
 * Copyright (C) 2019 Peng fei Pan <panpfpanpf@outlook.me>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package me.panpf.sketch.shaper;

import me.panpf.sketch.ImageView;
import me.panpf.sketch.decode.ResizeCalculator;
import me.panpf.sketch.request.ShapeSize;
import me.panpf.sketch.util.Utils;
import ohos.agp.render.*;
import ohos.agp.utils.Color;
import ohos.agp.utils.Matrix;
import ohos.agp.utils.Rect;
import ohos.agp.utils.RectFloat;
import ohos.app.Context;
import ohos.media.image.PixelMap;

/**
 * 圆形的绘制时图片整形器，还可以有描边
 */
public class CircleImageShaper implements ImageShaper {
    private int strokeWidth;
    private int strokeColor;

    private Paint strokePaint;
    private Rect boundsBack;
    private Path path;

    private Context context;
    private int resID = -1;
    private RectFloat rectSrc; //源区域
    private RectFloat rectDst; //目标区域

    private int componentWidth;
    private ResizeCalculator resizeCalculator;
    private int mImageHeight;

    public CircleImageShaper setContext(Context context) {
        this.context = context;
        return this;
    }

    public CircleImageShaper setResID(int resID) {
        this.resID = resID;
        rectSrc = new RectFloat(0, 0, 0, 0);
        rectDst = new RectFloat(0, 0, 0, 0);
        resizeCalculator = new ResizeCalculator();
        return this;
    }

    public CircleImageShaper setComponentWidth(int componentWidth) {
        this.componentWidth = componentWidth;
        return this;
    }

    public CircleImageShaper setImageHeight(int imageHeight) {
        this.mImageHeight = imageHeight;
        return this;
    }

    public int getStrokeColor() {
        return strokeColor;
    }

    public CircleImageShaper setStroke(int strokeColor, int strokeWidth) {
        this.strokeColor = strokeColor;
        this.strokeWidth = strokeWidth;
        updatePaint();
        return this;
    }

    public int getStrokeWidth() {
        return strokeWidth;
    }

    private void updatePaint() {
        if (strokeColor != 0 && strokeWidth > 0) {
            if (strokePaint == null) {
                strokePaint = new Paint();
                strokePaint.setStyle(Paint.Style.STROKE_STYLE);
                strokePaint.setAntiAlias(true);
            }

            strokePaint.setColor(new Color(strokeColor));
            strokePaint.setStrokeWidth(strokeWidth);
        }
    }

    @Override
    public Path getPath(Rect bounds) {
        if (path != null && boundsBack != null && boundsBack.equals(bounds)) {
            return path;
        }

        if (boundsBack == null) {
            boundsBack = new Rect();
        }
        boundsBack.set(bounds.left, bounds.top, bounds.right, bounds.bottom);

        if (path == null) {
            path = new Path();
        }
        path.reset();

        int centerX = bounds.getCenterX();
        int centerY = bounds.getCenterY();
        int radius = Math.max(centerX - bounds.left, centerY - bounds.top);
        path.addCircle(centerX, centerY, radius, Path.Direction.CLOCK_WISE);

        return path;
    }

    @Override
    public void onUpdateShaderMatrix(Matrix matrix, Rect bounds, int bitmapWidth, int bitmapHeight,
                                     ShapeSize shapeSize, Rect srcRect) {

    }


    @Override
    public void draw(Canvas canvas, Paint paint, Rect bounds) {
        final float widthRadius = bounds.getWidth() / 2f;
        final float heightRadius = bounds.getHeight() / 2f;

        paint.setAntiAlias(true);

        int centerOffsetX;
        int centerOffsetY;
        PixelMap pixelMap = Utils.getPixelMap(context, resID);
        if (pixelMap == null) {
            centerOffsetX = 0;
            centerOffsetY = 0;
        } else {
            centerOffsetX = (componentWidth - bounds.getWidth()) / 2;
            centerOffsetY = (mImageHeight - bounds.getHeight()) / 2;
        }

        final float cx = (float) ((double)bounds.left + widthRadius + centerOffsetX);
        final float cy = (float) ((double)bounds.top + heightRadius + centerOffsetY);
        final float radius = Math.min(widthRadius, heightRadius);

        if (pixelMap == null) {
            canvas.drawCircle(cx, cy, radius, paint);
        } else {
            ResizeCalculator.Mapping mapping = resizeCalculator.calculator(pixelMap.getImageInfo().size.width,
                    pixelMap.getImageInfo().size.height, componentWidth, componentWidth, ImageView.ScaleType.CLIP_CENTER, true);
            rectSrc.left = mapping.srcRect.left;
            rectSrc.top = mapping.srcRect.top;
            rectSrc.right = mapping.srcRect.right;
            rectSrc.bottom = mapping.srcRect.bottom;
            rectDst.modify(centerOffsetX, centerOffsetY, bounds.getWidth() + centerOffsetX, bounds.getHeight() + centerOffsetY);
            canvas.drawPixelMapHolderRoundRectShape(new PixelMapHolder(pixelMap), rectSrc, rectDst, widthRadius, heightRadius);
        }

        if (strokeColor != 0 && strokeWidth > 0 && strokePaint != null) {
            // 假如描边宽度是10，那么会是5个像素在图片外面，5个像素在图片里面，
            // 所以往图片里面偏移描边宽度的一半，让描边都在图片里面
            final float offset = strokeWidth / 2f;
            canvas.drawCircle(cx, cy, (float) (radius - (double)offset), strokePaint);
        }
    }

}
